﻿using NicoView.Model.Service.Comments;
using NicoView.Model.Service.Events;
using NicoView.Model.Service.Results;
using NicoView.Model.Timer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NicoView.Model.Service
{

    /// <summary>
    /// 各ニコニコサービスの元になるオブジェクト
    /// </summary>
    public abstract class NicoServiceBase:NicoViewObservableObject, INicoService
    {
        internal NicoServiceBase(NicoViewApplication baseServiceApplicationInstance)
        {
            this.BaseApplication = baseServiceApplicationInstance;

            this.endActionExecuting = false;
            this.Timer = new CommonDispatcherTimer();
            this.Timer.Interval = TimeSpan.FromSeconds(1);
            this.Timer.Tick += timer_Tick;
            this.activeWatchCount = 0;
        }

        public  virtual void Dispose()
        {
            this.CommentClient.Dispose();
        }

        private void timer_Tick(object sender, object e)
        {

            this.ServiceElapsedTime += this.Timer.Interval;
        }

        


        public abstract NicoServiceType ServiceType { get; }

        public CommonDispatcherTimer Timer { get; private set; }


        /// <summary>
        /// サービスに割り当てられた経過時間
        /// </summary>
        public TimeSpan ServiceElapsedTime
        {
            get
            {
                return this.serviceElapsedTime;
            }
            set
            {
                this.Set(() => this.ServiceElapsedTime, ref  this.serviceElapsedTime, value);

                if (this.ServiceElapsedTime.Seconds % 10 == 0)
                {
                    UpdateActiveWatchCount();
                }

                if (this.IsEndServiceTime)
                {
                    this.EndTimeActionAsync();
                }
            }
        }

        protected void UpdateActiveWatchCount()
        {
            this.ActiveWatchCount = this.CommentClient.CalcActiveWatchCount(this.ServiceElapsedTime);
        }

        

        private TimeSpan serviceElapsedTime;

        /// <summary>
        /// サービス終了時間か判定
        /// </summary>
        public bool IsEndServiceTime
        {
            get { return this.ServiceElapsedTime > this.ServiceInfo.EndElapsedTime; }
        }

        public int ActiveWatchCount
        {
            get
            {
                return this.activeWatchCount;
            }

            protected set
            {
                this.Set(() => this.ActiveWatchCount, ref this.activeWatchCount, value);
            }
        }

        private int activeWatchCount;


        private int watchCount;

        public int WatchCount
        {
            get
            {
                return this.watchCount;
            }
            protected set
            {
                this.Set(() => WatchCount, ref this.watchCount, value);
            }
        }


        private int commentCount;

        public int CommentCount
        {
            get
            {
                return this.commentCount;
            }
            
            protected set
            {
                this.Set(() => CommentCount, ref this.commentCount, value);
            }
        }

        #region 終了時処理関連
        private bool endActionExecuting;

        protected async void EndTimeActionAsync()
        {
            lock (this)
            {
                if (this.endActionExecuting)
                {
                    return;
                }
                this.endActionExecuting = true;
            }

            try
            {


                var result = await OnEndTimeActionAsync();

                if (!result.Succeed)
                {
                    this.BaseApplication.OnNotifyWaning(new NicoWarningEventArgs(null, result.Message));
                }

            }
            finally
            {
                lock (this)
                {
                    this.endActionExecuting = false;
                }

            }

        }
        #endregion

        


        #region 抽象
        protected abstract  Task<IResult> OnEndTimeActionAsync();

        public abstract INicoCommentClient CommentClient { get; }

        public abstract INicoServiceInfo ServiceInfo { get; }

        internal NicoViewApplication BaseApplication { get; private set; }

        internal abstract event NicoCommentGetUserRequestHandler UserRequest;
        #endregion


        
    }
}
